package com.sxf.core.record;

import com.sxf.core.record.dao.SourceRecordMapper;
import com.sxf.core.record.threadlocal.RecordDataThreadLocal;
import com.sxf.utils.JacksonUtils;
import org.apache.commons.collections.CollectionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @description: 记录请求参数
 * @author: author
 * @date:
 */
@Aspect
@Configuration
public class RecordAspect {

	@Pointcut("execution(* com.sxf..controller.*Controller.*(..)) " + " && "
	        + "!execution(* com.sxf.auth.captcha.controller.ImageVerifyCodeController.getImageVerifyCode(..)) ")
	public void paramAspect() {
	}

	@Pointcut("execution(* com.sxf.core.advice.ExceptionHandleAdvice.*(..)) ")
	public void resultAspect() {
	}
	
	@Autowired
	private SourceRecordMapper sourceRecordMapper;

	@Around("paramAspect()")
	public Object param(ProceedingJoinPoint pjp) throws Throwable {

		Integer success = 0;
		Object result = null;
		try {
			result = pjp.proceed();
		} catch (Throwable e) {
			success = 1;
			throw e;
		} finally {
			RecordDataThreadLocal.setReq(JacksonUtils.toJsonString(dealParams(pjp.getArgs())));
			RecordDataThreadLocal.setRes(Objects.isNull(result) ? null : JacksonUtils.toJsonString(result), success);
		}
		return result;
	}

	@AfterReturning(value = "resultAspect()", returning = "result")
	public void result(JoinPoint joinPoint, Object result) {
		Object[] params = joinPoint.getArgs();
		if (params.length == 2 && params[1] instanceof MethodArgumentNotValidException) {
			MethodArgumentNotValidException exception = (MethodArgumentNotValidException) params[1];
			Object obj = exception.getBindingResult().getTarget();
			if (!Objects.isNull(obj)) {
				RecordDataThreadLocal.setReq(JacksonUtils.toJsonString(obj));
			}
		}

		RecordDataThreadLocal.setRes(Objects.isNull(result) ? null : JacksonUtils.toJsonString(result), 1);
	}
	
//	@Around("restExecuteAspect()")
//	public Object restExecuteAspect(ProceedingJoinPoint pjp) throws Throwable {
//		SourceRecord sourceRecord = new SourceRecord();
//
//		Integer success = 0;
//		Object result = null;
//		try {
//			Object[] params = pjp.getArgs();
//			sourceRecord.setUrl(String.valueOf(params[0]));
//			sourceRecord.setRequest(Objects.isNull(params[1]) ? null : JacksonUtils.toJsonString(params[1]));
//
//			if(params.length == 4) {
//				sourceRecord.setHeader(Objects.isNull(params[3]) ? null : JacksonUtils.toJsonString(params[3]));
//			}
//			sourceRecord.setCreateTime(new Date());
//
//			result = pjp.proceed();
//			if(!Objects.isNull(result)) {
//				sourceRecord.setResponse(JacksonUtils.toJsonString(result));
//			}
//		} catch (Throwable e) {
//			success = 1;
//			sourceRecord.setResponse(e.getMessage());
//			throw e;
//		} finally {
//			if(sourceRecord.getUrl().indexOf("/external/basicinfo-server/credential/ocr") == -1) {
//				sourceRecord.setSuccess(success);
//				sourceRecordMapper.insert(sourceRecord);
//			}
//		}
//		return result;
//	}

	private List<Object> dealParams(Object[] sourceParams) {
		List<Object> params = new ArrayList<Object>();
		for (Object param : sourceParams) {
			if((param instanceof HttpServletRequest ) || (param instanceof HttpServletResponse )) {
				continue;
			} if (param instanceof MultipartFile) {
				MultipartFile multipartFile = (MultipartFile) param;
				params.add(new FileParam(multipartFile.getOriginalFilename(), multipartFile.getSize()));
			} else if (param instanceof List) {
				List<?> arrayValues = (List<?>) param;
				if (CollectionUtils.isEmpty(arrayValues) || !(arrayValues.get(0) instanceof MultipartFile)) {
					params.add(param);
				} else {
					List<FileParam> fileInfoList = new ArrayList<>();
					for (Object arrayValue : arrayValues) {
						MultipartFile multipartFile = (MultipartFile) arrayValue;
						fileInfoList.add(new FileParam(multipartFile.getOriginalFilename(), multipartFile.getSize()));
					}
					params.add(fileInfoList);
				}
			} else {
				params.add(param);
			}
		}
		return params;
	}

	class FileParam {

		private String fileName;
		private Long size;

		public FileParam(String fileName, Long size) {
			this.fileName = fileName;
			this.size = size;
		}

		public FileParam() {
		}

		public String getFileName() {
			return fileName;
		}

		public void setFileName(String fileName) {
			this.fileName = fileName;
		}

		public Long getSize() {
			return size;
		}

		public void setSize(Long size) {
			this.size = size;
		}

	}
}
